#include"core/task.h"
#include"tools/klib.h"
#include"os_cfg.h"
#include"cpu/cpu.h"
#include"cpu/irq.h"
#include"comm/cpu_instr.h"
#include"core/memory.h"
#include"ipc/mutex.h"
#include"cpu/mmu.h"
#include"core/syscall.h"
#include"comm/elf.h"
#include"fs/fs.h"

//任务管理器
static task_mananger_t task_mananger;
//空先进程的栈
static uint32_t idle_task_stack[1024];
//任务块分配结构
static task_t task_table[TSAK_NR];
//锁
static mutex_t task_table_mutex;



file_t * task_file (int fd)
{
    if ((fd >= 0) && (fd < TASK_OPENFILE_SIZE)) 
    {
        file_t * file = cur_task()->file_table[fd];
        return file;
    }
    return (file_t *)0;
}

int task_alloc_fd (file_t * file)
{
    task_t * task = cur_task();
    for (int i = 0; i < TASK_OPENFILE_SIZE; i++) 
    {
        file_t * p = task->file_table[i];
        if (p == (file_t *)0) 
        {
            task->file_table[i] = file;
            return i;
        }
    }

    return -1;
}

void task_remove_fd (int fd)
{
    if ((fd >= 0) && (fd < TASK_OPENFILE_SIZE)) 
    {
        cur_task()->file_table[fd] = (file_t *)0;
    }
}



int tss_init(task_t* task,int flag,uint32_t entry,uint32_t esp)
{
    int tss_sel=search_gdt_empty();
    task->tss_sel=tss_sel;
    if(tss_sel < 0)
    {
        print_log("alloc tss failed.\n");
        return -1;
    }
    //设置全局段描述符表
    set_global_segment(tss_sel>>3,(uint32_t)&task->tss,sizeof(tss_t),SEG_P | SEG_DPL0 | SEG_TYPE_TSS);
    kernel_memset(&task->tss,0,sizeof(tss_t));

    //创建内核栈
    uint32_t kernel_stack = memory_alloc_page();
    if (kernel_stack == 0) {
        goto tss_init_failed;
    }

    int code_sel,data_sel;
    if(flag & TASK_FLAG_SYSTEAM)
    {
        code_sel= KERNEL_CS << 3;
        data_sel= KERNEL_DS << 3;
    }
    else
    {
        code_sel=task_mananger.app_code_sel | SEG_CPL3;
        data_sel=task_mananger.app_data_sel | SEG_CPL3;
    }

    task->tss.eip=entry;
    task->tss.esp=esp;
    task->tss.esp0=kernel_stack+PAGE_SIZE;
    task->tss.ss=data_sel;
    task->tss.ss0=KERNEL_DS << 3;
    task->tss.es=task->tss.ds=task->tss.fs=task->tss.gs= data_sel;
    task->tss.cs= code_sel;
    task->tss.eflags= EFLAGES_IF | EFLAGES_DEFAULT; 
     
    uint32_t page_dir = memory_create_uvm();
    if(page_dir == 0)
    {
        goto tss_init_failed;
    }
    //创建成功
    task->tss.cr3 = page_dir;

    return 0;

tss_init_failed:
    gdt_free_sel(tss_sel);
    if (kernel_stack) {
        memory_free_page(kernel_stack);
    }
    return -1;
}



int task_init(task_t* task,int flag,const char* name,uint32_t entry,uint32_t esp)
{

    ASSERT(task!=0);
    irq_state state= int_enter_protection();
    
    tss_init(task,flag,entry,esp);
    kernel_strncpy(task->name,name,TASK_NAME_SIZE);
    task->state=TASK_CREATED;
    task->time_ticks=TASK_TIME_SLICE_DEFAULT;
    task->slice_ticks=task->time_ticks;
    task->sleep_ticks=0;
    task->heap_start=0;
    task->heap_end=0;
    task->status=0;
    task->parent=(task_t*)0;
    task->pid=(uint32_t)task;

    kernel_memset(task->file_table, 0, sizeof(task->file_table));

    list_node_init(&task->all_node);
    list_node_init(&task->run_node);
    list_node_init(&task->wait_node);

    list_insert_last(&task_mananger.task_list,&task->all_node);

    int_leave_protection(state);

    return 0;
}


void task_start(task_t* task)
{
    irq_state state= int_enter_protection();
    task_set_ready(task);
    int_leave_protection(state);
}

task_t* task_next_run()
{
    if(task_mananger.ready_list.count==0)
    {
        return &task_mananger.idle_task;
    }
    list_node* task_node= task_mananger.ready_list.first;
    return list_node_parent(task_node,task_t,run_node);
}

//进程切换
void task_switch_from_to(task_t* from,task_t* to)
{
    switch_to_tss(to->tss_sel);
    //在栈中压入参数与返回地址
    //simple_switch(&from->stack,to->stack);
}

void task_first_init()
{
    extern uint8_t s_first_task[],e_first_task[];

    uint32_t copy_size=(uint32_t)(e_first_task - s_first_task);
    uint32_t alloc_size=10 * PAGE_SIZE;    

    void first_task_entry();
    uint32_t first_start = (uint32_t)first_task_entry;
    task_init(&task_mananger.first_task,0,"first_task",first_start,first_start + alloc_size);
    //设置堆区
    task_mananger.first_task.heap_start=(uint32_t)e_first_task;
    task_mananger.first_task.heap_end=(uint32_t)e_first_task;
    write_tr(task_mananger.first_task.tss_sel);
    task_mananger.cur_task=&task_mananger.first_task;
    //切换页表
    mmu_set_page_dir(task_mananger.first_task.tss.cr3);
    memory_alloc_page_for(first_start,alloc_size,PTE_P | PTE_W | PTE_U);
    //拷贝至指定地址
    kernel_memcpy((void*)first_start,s_first_task,copy_size);
    task_start(&task_mananger.first_task);
}

task_t* task_first()
{
    return &task_mananger.first_task;
}

static void idle_task_entry()
{
    while(1)
    {
        hlt();
    }
}

void task_mananger_init()
{
    //清空进程分配块
    kernel_memset(task_table,0,sizeof(task_table));
    mutex_init(&task_table_mutex);
    // 设置数据段
    int sel = search_gdt_empty();
    set_global_segment(sel >> 3 ,0x000000000,0xFFFFFFFF,SEG_P | SEG_DPL3 | SEG_S_NORMAL |SEG_TYPE_DATA | SEG_TYPE_RW | SEG_D);
    task_mananger.app_data_sel = sel;

    //设置代码段
    sel = search_gdt_empty();
    set_global_segment(sel >> 3,0x000000000,0xFFFFFFFF,SEG_P | SEG_DPL3 | SEG_S_NORMAL |SEG_TYPE_CODE | SEG_TYPE_RW | SEG_D);
    task_mananger.app_code_sel = sel;

    list_init(&task_mananger.ready_list);
    list_init(&task_mananger.task_list);
    list_init(&task_mananger.sleep_list);
    task_mananger.cur_task=(task_t*)0; 
    //初始化默认进程    默认进程会在其他所有进程睡眠时加入就绪队列
    task_init(&task_mananger.idle_task,TASK_FLAG_SYSTEAM,"idle_task",(uint32_t)idle_task_entry,(uint32_t)idle_task_stack+1024);
    task_start(&task_mananger.idle_task);
}

void task_set_ready(task_t* task)
{
    if(task==&task_mananger.idle_task)
    {
        return;
    }
    list_insert_last(&task_mananger.ready_list,&task->run_node);
    task->state=TASK_READY;
}


void task_set_block(task_t* task)
{
    if(task==&task_mananger.idle_task)
    {
        return;
    }
    list_remove(&task_mananger.ready_list,&task->run_node);
}

int sys_sched_yield()
{
    if(list_count(&task_mananger.ready_list)>1)
    {
        //添加到队尾
        task_t* cur_task=task_mananger.cur_task;
        task_set_block(cur_task);
        task_set_ready(cur_task);

        task_dispatch();
    }
}


void task_dispatch()
{
    task_t * to=task_next_run();
    if(to != task_mananger.cur_task)
    {
        task_t* from= task_mananger.cur_task;

        task_mananger.cur_task=to;
        to->state=TASK_RUNNING;

        task_switch_from_to(from,to);
    }
}

void task_time_tick()
{
    task_t* cur_task=task_mananger.cur_task;


    if(--cur_task->slice_ticks == 0)
    {
        cur_task->slice_ticks=cur_task->time_ticks;
        task_set_block(cur_task);
        task_set_ready(cur_task);

        task_dispatch();
    }

    //唤醒睡眠进程
    list_node* cur = task_mananger.sleep_list.first;

    while (cur)
    {
        list_node* next= cur->next;
        task_t* task=list_node_parent(cur,task_t,run_node);
        if(--task->sleep_ticks==0)
        {
            task_set_wakeup(task);
            task_set_ready(task);
        }
        cur=next;
    }
    task_dispatch();
}


void task_set_sleep(task_t* task,uint32_t ticks)
{
    if(ticks==0)
    {
        return;
    }

    task->sleep_ticks=ticks;
    task->state=TASK_SLEEP;
    list_insert_last(&task_mananger.sleep_list,&task->run_node);

}

void task_set_wakeup(task_t* task)
{
    list_remove(&task_mananger.sleep_list,&task->run_node);
}


void sys_sleep(uint32_t ms)
{
    task_set_block(task_mananger.cur_task);

    task_set_sleep(task_mananger.cur_task,(ms+(OS_TICKS_MS))/OS_TICKS_MS);
    
    //切换
    task_dispatch();
}


task_t* cur_task()
{
    return task_mananger.cur_task;
}


int sys_getpid()
{
    return cur_task()->pid;
}


static task_t* alloc_task()
{
    task_t* task = (task_t*)0;

    mutex_lock(&task_table_mutex);

    for(int i=0;i<TSAK_NR;i++)
    {
        task_t* cur=task_table+i;
        if(cur->name[0] == '\0')
        {
            task = cur;
            break;
        }
    }
    mutex_unlock(&task_table_mutex);

    return task;
}


static void free_task(task_t* task)
{
    mutex_lock(&task_table_mutex);
    task->name[0]='\0';
    mutex_unlock(&task_table_mutex);
}


void task_uninit(task_t * task)
{
    if(task->tss_sel)
    {
        gdt_free_sel(task->tss_sel);
    }

    if(task->tss.esp0)
    {
        //释放内核栈
        memory_free_page(task->tss.esp0 - PAGE_SIZE);
    }  
    if(task->tss.cr3)
    {
        memory_destroy_uvm(task->tss.cr3);
    }

    kernel_memset(task,0,sizeof(task_t));
}

//从当前进程中拷贝已经打开的文件列表
static void copy_opened_files(task_t * child_task) 
{
    task_t * parent = cur_task();

    for (int i = 0; i < TASK_OPENFILE_SIZE; i++) 
    {
        file_t * file = parent->file_table[i];
        if (file) 
        {
            file_inc_ref(file);
            child_task->file_table[i] = parent->file_table[i];
        }
    }
}


int sys_fork()
{
    //父进程
    task_t * parent_task = cur_task();
    //子进程
    task_t * child_task = alloc_task();
    if(child_task == (task_t*)0)
    {
        goto fork_failed;
    }
    //取得父进程状态
    syscall_frame_t* frame = (syscall_frame_t*)(parent_task->tss.esp0 - sizeof(syscall_frame_t));
    int err = task_init(child_task,0,parent_task->name,frame->eip,frame->esp+sizeof(uint32_t)*SYSCALL_PARAM_COUNT);

    if(err < 0)
    {
        goto fork_failed;
    }

    copy_opened_files(child_task);

    tss_t* tss = &child_task->tss;
    tss->eax = 0;                       // 子进程返回0
    tss->ebx = frame->ebx;
    tss->ecx = frame->ecx;
    tss->edx = frame->edx;
    tss->esi = frame->esi;
    tss->edi = frame->edi;
    tss->ebp = frame->ebp;

    tss->cs = frame->cs;
    tss->ds = frame->ds;
    tss->es = frame->es;
    tss->fs = frame->fs;
    tss->gs = frame->gs;
    tss->eflags = frame->eflags;

    child_task->parent = parent_task;

    //复制父进程的内存空间到子进程
    if ((child_task->tss.cr3 = memory_copy_uvm(parent_task->tss.cr3)) < 0) 
    {
        goto fork_failed;
    }
    task_start(child_task);
    return child_task->pid;
fork_failed:
    if(child_task) 
    {
        task_uninit(child_task);
        free_task(child_task);
    }
    return -1;
}




static int load_phdr(int file, Elf32_Phdr * phdr, uint32_t page_dir) 
{
    // 生成的ELF文件要求是页边界对齐的
    ASSERT((phdr->p_vaddr & (PAGE_SIZE - 1)) == 0);

    //分配空间
    int err = memory_alloc_for_page_dir(page_dir, phdr->p_vaddr, phdr->p_memsz, PTE_P | PTE_U | PTE_W);
    if (err < 0) 
    {
        print_log("no memory");
        return -1;
    }

    // 调整当前的读写位置
    if (sys_lseek(file,phdr->p_offset, 0) < 0) 
    {
        print_log("read file failed");
        return -1;
    }

    uint32_t vaddr = phdr->p_vaddr;
    uint32_t size =  phdr->p_filesz;
    while (size > 0) 
    {
        int curr_size = (size > PAGE_SIZE) ? PAGE_SIZE : size;
        //得到新页表 虚拟地址对应的物理地址
        uint32_t paddr = memory_get_paddr(page_dir, vaddr);

        if (sys_read(file, (char *)paddr, curr_size) <  curr_size) 
        {
            print_log("read file failed");
            return -1;
        }

        size -= curr_size;
        vaddr += curr_size;
    }

    return 0;
}



static uint32_t load_elf_file(task_t* task,const char* name,uint32_t page_dir)
{
    Elf32_Ehdr elf_hdr;
    Elf32_Phdr elf_phdr;

    int file=sys_open(name,0);
    if(file<0)
    {
        print_log("open filed.%s",name);
        goto load_failed;
    }
    int cnt = sys_read(file,(char*)&elf_hdr,sizeof(elf_hdr));
    if (cnt < sizeof(Elf32_Ehdr)) 
    {
        print_log("elf hdr too small. size=%d", cnt);
        goto load_failed;
    }

    //必要性的检查
    if ((elf_hdr.e_ident[0] != ELF_MAGIC) || (elf_hdr.e_ident[1] != 'E')
        || (elf_hdr.e_ident[2] != 'L') || (elf_hdr.e_ident[3] != 'F')) {
        print_log("check elf indent failed.");
        goto load_failed;
    }

    // 必须是可执行文件和针对386处理器的类型，且有入口
    if ((elf_hdr.e_type != ET_EXEC) || (elf_hdr.e_machine != ET_386) || (elf_hdr.e_entry == 0)) {
        print_log("check elf type or entry failed.");
        goto load_failed;
    }

    // 必须有程序头部
    if ((elf_hdr.e_phentsize == 0) || (elf_hdr.e_phoff == 0)) {
        print_log("none programe header");
        goto load_failed;
    }

    // 然后从中加载程序头，将内容拷贝到相应的位置
    uint32_t e_phoff = elf_hdr.e_phoff;
    for (int i = 0; i < elf_hdr.e_phnum; i++, e_phoff += elf_hdr.e_phentsize) 
    {
        if (sys_lseek(file, e_phoff, 0) < 0) {
            print_log("read file failed");
            goto load_failed;
        }

        cnt = sys_read(file, (char *)&elf_phdr, sizeof(Elf32_Phdr));
        if (cnt < sizeof(Elf32_Phdr)) {
            print_log("read file failed");
            goto load_failed;
        }

        if ((elf_phdr.p_type != PT_LOAD) || (elf_phdr.p_vaddr < MEM_TASK_BASE)) 
        {
           continue;
        }

        int err = load_phdr(file, &elf_phdr, page_dir);
        if (err < 0) 
        {
            print_log("load program hdr failed");
            goto load_failed;
        }
        //设置堆大小
        task->heap_start = elf_phdr.p_vaddr + elf_phdr.p_memsz;
        task->heap_end = task->heap_start;
   }

    sys_close(file);
    return elf_hdr.e_entry;

load_failed:
    if(file >= 0) 
    {
        sys_close(file);
    }

    return 0;
}


static int copy_args(char* to, uint32_t page_dir, int argc, char **argv) 
{
    // 在stack_top中依次写入argc, argv指针，参数字符串
    task_args_t task_args;
    task_args.argc = argc;
    task_args.argv = (char **)(to + sizeof(task_args_t));

    // 复制各项参数, 跳过task_args和参数表
    // 各argv参数写入的内存空间
    char * dest_arg = to + sizeof(task_args_t) + sizeof(char *) * (argc + 1);   // 留出结束符
    
    // argv表
    char ** dest_argv_tb = (char **)memory_get_paddr(page_dir, (uint32_t)(to + sizeof(task_args_t)));
    ASSERT(dest_argv_tb != 0);

    for (int i = 0; i < argc; i++) 
    {
        char * from = argv[i];

        // 不能用kernel_strcpy，因为to和argv不在一个页表里
        int len = kernel_strlen(from) + 1;   //包含结束符
        int err = memory_copy_uvm_data((uint32_t)dest_arg, page_dir, (uint32_t)from, len);
        ASSERT(err >= 0);

        // 关联ar
        dest_argv_tb[i] = dest_arg;
        dest_arg += len;
    }
    
    if(argc)
    {
        dest_argv_tb[argc] = '\0';
    }
     // 写入task_args
    return memory_copy_uvm_data((uint32_t)to, page_dir, (uint32_t)&task_args, sizeof(task_args_t));
}



int sys_execve(char* name,char** argv,char** env)
{
    task_t* task = cur_task();
    kernel_strncpy(task->name,get_file_name(name),TASK_NAME_SIZE);

    uint32_t old_page_dir=task->tss.cr3;
    //创建页目录
    uint32_t new_page_dir = memory_create_uvm();
    if(!new_page_dir)
    {
        goto exec_failed;
    }

    uint32_t entry= load_elf_file(task,name,new_page_dir);
    if(entry == 0)
    {
        goto exec_failed;
    }

    //分配栈空间
    uint32_t stack_top = MEM_STACK_TOP - MEM_TASK_ARG_SIZE;
    int err = memory_alloc_for_page_dir(new_page_dir,MEM_STACK_TOP-MEM_STACK_SIZE,MEM_STACK_SIZE,PTE_P | PTE_U | PTE_W);
    if(err < 0)
    {
        goto exec_failed;
    }

    int argc = strings_count(argv);

    //拷贝参数
    err = copy_args((char*)stack_top,new_page_dir,argc,argv);
    if(err < 0)
    {
        goto exec_failed;
    }

    //更改返回地址
    syscall_frame_t* frame = (syscall_frame_t*)(task->tss.esp0 - sizeof(syscall_frame_t));
    frame->eip = entry;
    frame->eax = frame->ebx = frame->ecx = frame->edx = 0;
    frame->esi = frame->edi = frame->ebp = 0;
    frame->eflags = EFLAGES_IF | EFLAGES_DEFAULT; 

    //设置
    frame->esp = stack_top - sizeof(uint32_t)*SYSCALL_PARAM_COUNT;

    task->tss.cr3=new_page_dir;
    mmu_set_page_dir(new_page_dir);

    memory_destroy_uvm(old_page_dir);

    return 0;
exec_failed:
    if(new_page_dir)
    {
        task->tss.cr3=old_page_dir;
        mmu_set_page_dir(old_page_dir);
        memory_destroy_uvm(new_page_dir);
    }
    return -1;
}

void sys_exit(int status)
{
    task_t * curr_task = cur_task();

    // 关闭所有打开的文件
    for (int fd = 0; fd < TASK_OPENFILE_SIZE; fd++) 
    {
        file_t * file = curr_task->file_table[fd];
        if (file) 
        {
            sys_close(fd);
            curr_task->file_table[fd] = (file_t *)0;
        }
    }

    int move_child = 0;

   // 将所有子进程父进程设为init进程

    mutex_lock(&task_table_mutex);

    for (int i = 0; i < TSAK_NR ; i++) 
    {
        task_t * task = task_table + i;
        if (task->parent == curr_task) 
        {
            // 有子进程，则转给init_task
            task->parent = &task_mananger.first_task;

            // 如果子进程中有僵尸进程，唤醒回收资源
            // 并不由自己回收，因为自己将要退出
            if (task->state == TASK_ZOMBIE) 
            {
                move_child = 1;
            }
        }
    }

    mutex_unlock(&task_table_mutex);



    irq_state state = int_enter_protection();

    task_t*  parent = cur_task()->parent;

    if(parent->state = TASK_WAITTING)
    {
        task_set_ready(cur_task()->parent);
    }

    // 保存返回值，进入僵尸状态
    curr_task->status = status;
    curr_task->state = TASK_ZOMBIE;
    task_set_block(curr_task);
    task_dispatch();

    int_leave_protection(state);
}


int sys_wait(int* status)
{
    task_t * curr_task = cur_task();

    for (;;) 
    {
        // 遍历，找僵尸状态的进程，然后回收。否则进入睡眠态
        mutex_lock(&task_table_mutex);
        for (int i = 0; i < TSAK_NR; i++) 
        {
            task_t * task = task_table + i;
            if (task->parent != curr_task) 
            {
                continue;
            }

            if (task->state == TASK_ZOMBIE) 
            {
                int pid = task->pid;

                *status = task->status;

                memory_destroy_uvm(task->tss.cr3);
                memory_free_page(task->tss.esp0 - PAGE_SIZE);
                kernel_memset(task, 0, sizeof(task_t));

                mutex_unlock(&task_table_mutex);
                return pid;
            }
        }
        mutex_unlock(&task_table_mutex);

        // 找不到，则等待
        irq_state state = int_enter_protection();

        task_set_block(curr_task);
        curr_task->state = TASK_WAITTING;
        task_dispatch();

        int_leave_protection(state);
    }
}